home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / System 7.0 Samples / ProcDoggie 1.0a6 / ProcDoggie.p < prev    next >
Encoding:
Text File  |  1994-11-18  |  17.8 KB  |  585 lines  |  [TEXT/MPS ]

  1. PROGRAM ProcDoggie;
  2.  
  3. {-------------------------------------------------------------------------------
  4. #
  5. #    Apple Macintosh Developer Technical Support
  6. #
  7. #    Main program file for the ProcDoggie application
  8. #
  9. #    Program:    ProcDoggie
  10. #    File:        ProcDoggie.p - Pascal Implementation
  11. #
  12. #    by:        Forrest Tanaka
  13. #
  14. #    Copyright © 1988-1991 Apple Computer, Inc.
  15. #    All rights reserved.
  16. #
  17. --------------------------------------------------------------------------------
  18. #
  19. #    ProcDoggie.p is the root file for ProcDoggie.  It contains the main entry
  20. #    point and the PROGRAM statement, but relies on the other source files
  21. #    included with this application to actually implement the functionality.
  22. #
  23. -------------------------------------------------------------------------------}
  24. {[j=20/57/1$] Pasmat Options}
  25. {$R-}
  26.     
  27.  
  28. (*******************************************************************************
  29. * Used Units
  30. *******************************************************************************)
  31.  
  32.     USES
  33.         (* Group 1 *)
  34.          Types
  35.         ,QuickDraw
  36.  
  37.         (* Group 2 *)
  38.         ,AppleEvents
  39.         ,Controls
  40.         ,DiskInit
  41.         ,Errors
  42.         ,Events
  43.         ,Fonts
  44.         ,Memory
  45.         ,Menus
  46.         ,SegLoad
  47.  
  48.         (* Group 3 *)
  49.         ,Processes
  50.         ,Windows
  51.  
  52.         (* Group 4 *)
  53.         ,Dialogs
  54.         ,TextUtils
  55.         ,ToolUtils
  56.  
  57.         (* Application *)
  58.         ,UGlobals
  59.         ,UEmergMem
  60.         ,UProcessUtils
  61.         ,UMenuHandler
  62.         ,UProcessGuts
  63.         ;
  64.  
  65.  
  66. (*******************************************************************************
  67. * Constants
  68. *******************************************************************************)
  69.  
  70.     CONST
  71.         kBecomingActive = TRUE; {Pass to DoActivateEvt; indicates becoming active}
  72.  
  73.  
  74. (*******************************************************************************
  75. * Global Variables
  76. *******************************************************************************)
  77.  
  78.     VAR
  79.         gProcessListWind: WindowPtr; {Pointer to the process list window}
  80.  
  81.  
  82. {$S Main}
  83. (*******************************************************************************
  84. * DoneRequiredParams - Done processing required params; OK?
  85. *
  86. * DoneRequiredParams checks to see if the AppleEvent specified by the
  87. * anAppleEvent parameter has any required parameters that we haven’t yet
  88. * processed.  If there aren’t any left, then noErr is returned.  If there are
  89. * required parameters that haven’t been processed yet, then errAEEventNotHandled
  90. * is returned.  If any other errors occur, then that error code is returned.
  91. *******************************************************************************)
  92.  
  93.     FUNCTION DoneRequiredParams (anAppleEvent: AppleEvent): OSErr;
  94.  
  95.         VAR
  96.             typeCode:   DescType; {Type of AppleEvent attribute found; ignored}
  97.             actualSize: Size;     {Actual size of parameters; ignored}
  98.             error:      OSErr;
  99.  
  100.     BEGIN
  101.         (* Are there any required parameters in AppleEvent we didn’t process? *)
  102.        error := AEGetAttributePtr (anAppleEvent, keyMissedKeywordAttr,
  103.                 typeWildCard, (*<*)typeCode, NIL, 0, (*<*)actualSize);
  104.         IF error = errAEDescNotFound THEN
  105.             (* No required parameters left, so no error *)
  106.             DoneRequiredParams := noErr
  107.         ELSE IF error = noErr THEN
  108.             (* There was at least one required parameter we didn’t process *)
  109.             DoneRequiredParams := errAEEventNotHandled
  110.         ELSE
  111.             (* Some other error happened *)
  112.             DoneRequiredParams := error
  113.     END;
  114.  
  115.  
  116. {$S Main}
  117. (*******************************************************************************
  118. * HandleAEquit - Handler for 'quit' AppleEvent
  119. *
  120. * This is the AppleEvent handler for the 'quit' AppleEvent as passed in the
  121. * quitAppleEvent parameter by the AppleEvent Manager.  The DoQuit routine is
  122. * called which causes this application to quit at the start of the next
  123. * iteration of the main event loop.
  124. *
  125. * Though the quit AppleEvent doesn’t contain any parameters, the standard thing
  126. * to do in reaction to any AppleEvent is to check to see if there are any
  127. * required parameters in the AppleEvent that this routine doesn’t recognise.
  128. * DoneRequiredParms checks for this condition and returns an error if there are
  129. * in fact required parameters in the AppleEvent or if some other error occurs
  130. * during the check.
  131. *******************************************************************************)
  132.  
  133.     FUNCTION HandleAEquit (quitAppleEvent: AppleEvent;
  134.                            reply:          AppleEvent;
  135.                            handlerRefCon:  LongInt): OSErr;
  136.  
  137.         VAR
  138.             error: OSErr;
  139.  
  140.         PROCEDURE RecoverError (errorCode: OSErr);
  141.  
  142.         BEGIN
  143.             HandleAEquit := errorCode;
  144.             EXIT (HandleAEquit)
  145.         END;
  146.  
  147.     BEGIN
  148.         (* quit AE has no parms, but check in case the client requires any *)
  149.         error := DoneRequiredParams (quitAppleEvent);
  150.         IF error <> noErr THEN
  151.             RecoverError (error);
  152.  
  153.         (* Handle the Quit command *)
  154.         DoQuit;
  155.         HandleAEquit := noErr
  156.     END;
  157.  
  158.  
  159. {$S %A5Init}
  160. (*******************************************************************************
  161. * StartUp - Do whatever has to be done to initialize the application
  162. *
  163. * This routine is called after the heap is initialized to initialize the
  164. * application.  This involves initializing the toolbox, emergency memory, and
  165. * loading up the menus.  If any errors occur while doing this, StartUp displays
  166. * an alert telling the user what the error was and then ExitToShell is called.
  167. * This is an unusual way to react to errors, and I only do it here because it’s
  168. * so early in execution that there really isn’t much else that can be done.
  169. *
  170. * See this UEmergMem unit in this application for details about emergency
  171. * memory.
  172. *******************************************************************************)
  173.  
  174.     PROCEDURE StartUp;
  175.  
  176.         CONST
  177.             kSysHandler = TRUE; {Specifies that AE handler is in system heap}
  178.  
  179.         VAR
  180.             error: OSErr;
  181.  
  182.         PROCEDURE HandleError (messageClass: Integer;
  183.                                messageIndex: Integer);
  184.  
  185.             VAR
  186.                 result: Integer; {Result of alert; ignored}
  187.  
  188.         BEGIN
  189.             result := ShowStopAlert (messageClass, messageIndex);
  190.             ExitToShell
  191.         END;
  192.  
  193.     BEGIN
  194.         (* Initialize the toolbox *)
  195.         InitGraf (@qd.thePort);
  196.         InitFonts;
  197.         InitWindows;
  198.         InitMenus;
  199.         TEInit;
  200.         InitDialogs (NIL);
  201.  
  202.         (* Initialize emergency memory *)
  203.         InitEmergMem;
  204.         IF FailLowMemory (0) THEN
  205.             HandleError (rMemErrMessages, kMemErrAppOpenMsg);
  206.  
  207.         (* Load the menus and draw the menu bar *)
  208.         StartMenus;
  209.         IF FailLowMemory (0) THEN
  210.             HandleError (rMemErrMessages, kMemErrAppOpenMsg)
  211.         ELSE IF gError <> noErr THEN
  212.             IF gError = memFullErr THEN
  213.                 HandleError (rMemErrMessages, kMemErrAppOpenMsg)
  214.             ELSE IF gError = resNotFound THEN
  215.                 HandleError (rResErrMessages, kResErrAppDamageMsg)
  216.             ELSE
  217.                 HandleError (rMiscErrMessages, kMiscErrUnknownMsg);
  218.  
  219.         (* Install the AppleEvent handler *)
  220.         error := AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
  221.                 @HandleAEquit, 0, NOT kSysHandler);
  222.         IF (error = memFullErr) | FailLowMemory (0) THEN
  223.             HandleError (rMemErrMessages, kMemErrAppOpenMsg)
  224.         ELSE IF error <> noErr THEN
  225.             HandleError (rMiscErrMessages, kMiscErrUnknownMsg)
  226.     END;
  227.  
  228.  
  229. {$S Main}
  230. (*******************************************************************************
  231. * Public: DoWindowDrag
  232. *
  233. * A rectangle that covers all screen can be retrieved from the desktop region’s
  234. * rgnBBox.  The desktop region can be retrieved by calling GetGrayRgn.
  235. *******************************************************************************)
  236.  
  237.     PROCEDURE DoWindowDrag (anEvent:       EventRecord;
  238.                             clickedWindow: WindowPtr);
  239.  
  240.         VAR
  241.             dragBounds: Rect; {Window can be dragged over this rectangle}
  242.  
  243.     BEGIN
  244.         (* GetGrayRgn^^.rgnBBox covers the desktop over all screens *)
  245.         dragBounds := GetGrayRgn^^.rgnBBox;
  246.         DragWindow (clickedWindow, anEvent.where, dragBounds)
  247.     END;
  248.  
  249.  
  250. {$S Main}
  251. (*******************************************************************************
  252. * Public: DoContentClick
  253. *
  254. * As new kinds of windows are added to this application, this routine will have
  255. * to be able to detect the new kind of window and dispatch to the routine that
  256. * handles clicks in that kind of window.
  257. *******************************************************************************)
  258.  
  259.     PROCEDURE DoContentClick (anEvent:       EventRecord;
  260.                               clickedWindow: WindowPtr);
  261.  
  262.         VAR
  263.             currWindow: WindowPtr; {Pointer to the current front window}
  264.  
  265.     BEGIN
  266.         currWindow := FrontWindow;
  267.  
  268.         (* Clicked window not in front; activate it *)
  269.         IF currWindow <> clickedWindow THEN
  270.             SelectWindow (clickedWindow)
  271.         ELSE
  272.             IF IsProcessListWindow (clickedWindow) THEN
  273.                 ClickProcessListWindow (clickedWindow, anEvent)
  274.     END;
  275.  
  276.  
  277. {$S Main}
  278. (*******************************************************************************
  279. * Public: DoUpdateEvt
  280. *
  281. * As new kinds of windows are added to this application, this routine will have
  282. * to be able to detect the new kind of window and dispatch to the routine that
  283. * handles update events in that kind of window.
  284. *******************************************************************************)
  285.  
  286.     PROCEDURE DoUpdateEvt (anEvent: EventRecord);
  287.  
  288.         VAR
  289.             eventWindow: WindowPtr; {Pointer to the window to update}
  290.  
  291.     BEGIN
  292.         eventWindow := WindowPtr(anEvent.message);
  293.  
  294.         (* Update the window that needs it *)
  295.         SetPort (eventWindow);
  296.         BeginUpdate (eventWindow);
  297.         IF IsProcessListWindow (eventWindow) THEN
  298.             DrawProcessListWindow (eventWindow)
  299.         ELSE IF IsProcessInfoWindow (eventWindow) THEN
  300.             DrawProcessInfoWindow (eventWindow);
  301.         EndUpdate (eventWindow)
  302.     END;
  303.  
  304.  
  305. {$S Main}
  306. (*******************************************************************************
  307. * Public: DoActivateEvt
  308. *
  309. * As new kinds of windows are added to this application, this routine will have
  310. * to be able to detect the new kind of window and dispatch to the routine that
  311. * handles activate events in that kind of window.
  312. *******************************************************************************)
  313.  
  314.     PROCEDURE DoActivateEvt (eventWind:      WindowPtr;
  315.                              becomingActive: Boolean);
  316.  
  317.     BEGIN
  318.         IF IsProcessListWindow (eventWind) THEN
  319.             ActivateProcessListWindow (eventWind, becomingActive);
  320.     END;
  321.  
  322.  
  323. {$S Main}
  324. (*******************************************************************************
  325. * Public: DoWindowClose
  326. *
  327. * As new kinds of windows are added to this application, this routine will have
  328. * to be able to detect the new kind of window and dispatch to the routine that
  329. * handles close requests for that kind of window.
  330. *******************************************************************************)
  331.  
  332.     PROCEDURE DoWindowClose (anEvent:   EventRecord;
  333.                              eventWind: WindowPtr);
  334.  
  335.     BEGIN
  336.         IF TrackGoAway (eventWind, anEvent.where) THEN
  337.             IF IsProcessInfoWindow (eventWind) THEN
  338.                 CloseProcessInfoWindow (eventWind);
  339.     END;
  340.  
  341.  
  342. {$S Main}
  343. (*******************************************************************************
  344. * DoMouseDown - Mouse-down event dispatcher
  345. *
  346. * When a mouseDown event is received in the main event loop, this routine is
  347. * called to determine which area on the screens the mouseDown was, and to
  348. * dispatch to the appropriate routine to handle mouseDown events in that area.
  349. * The mouseDown event is passed in the anEvent parameter.
  350. *
  351. * See the UMenuHandler unit for routines that handle mouse-down events in the
  352. * menu bar, and the UWindowHandler unit for routines that handle mouse-down
  353. * events in the windows.
  354. *******************************************************************************)
  355.  
  356.     PROCEDURE DoMouseDown (anEvent: EventRecord);
  357.  
  358.         VAR
  359.             clickArea: Integer;   {Area of the screen that was clicked}
  360.             eventWind: WindowPtr; {Pointer the clicked window, if any}
  361.  
  362.     BEGIN
  363.         (* Find clicked area of screen or window *)
  364.         clickArea := FindWindow (anEvent.where, (*<*)eventWind);
  365.  
  366.         (* Jump to mouseDown-handling routine appropriate for screen area *)
  367.         CASE clickArea OF
  368.             inMenuBar:
  369.                 DoMenuChoice (MenuSelect (anEvent.where));
  370.             inContent:
  371.                 DoContentClick (anEvent, eventWind);
  372.             inGoAway:
  373.                 DoWindowClose (anEvent, eventWind);
  374.             inDrag:
  375.                 DoWindowDrag (anEvent, eventWind)
  376.         END
  377.     END;
  378.  
  379.  
  380. {$S Main}
  381. (*******************************************************************************
  382. * DoKeyDown - Key-down event dispatcher
  383. *
  384. * When a keyDown or autoKey event is received in the main event loop, this
  385. * routine is called to determine whether key is a command-key equivalent for a
  386. * menu item or not.  If the command key isn’t down, then the key stroke is
  387. * ignored.  Otherwise, MenuKey is called to get the menu ID and item number
  388. * of the menu item that corresponds to the command key, if any.  Then
  389. * DoMenuChoice is called to dispatch to the appropriate routine for the chosen
  390. * menu item.  The keyDown or autoKey event is passed in anEvent.
  391. *
  392. * See the UMenuHandler unit for routines that handle menu events.
  393. *******************************************************************************)
  394.  
  395.     PROCEDURE DoKeyDown (anEvent: EventRecord);
  396.  
  397.         VAR
  398.             theKey: Char; {ASCII code of key that was pressed}
  399.  
  400.     BEGIN
  401.         (* Get the ASCII code of the pressed key *)
  402.         theKey := CHR (BAND (anEvent.message, charCodeMask));
  403.  
  404.         (* If anEvent was keyDown and command key was down, it’s menu command *)
  405.         IF (anEvent.what = keyDown) AND (BAND (anEvent.modifiers, cmdKey) <> 0)
  406.                 THEN
  407.             DoMenuChoice (MenuKey (theKey))
  408.     END;
  409.  
  410.  
  411. {$S Main}
  412. (*******************************************************************************
  413. * DoDiskEvt - Handle a disk-insert event
  414. *
  415. * This routine is called whenever this application receives an event indicating
  416. * that a disk was inserted.  If the disk can’t be mounted, the message field of
  417. * the event reflects the error, and we call DIBadMount to allow the user to
  418. * format the disk.
  419. *******************************************************************************)
  420.  
  421.     PROCEDURE DoDiskEvt (anEvent: EventRecord);
  422.  
  423.         CONST
  424.             kSysAlertLeft = 80; {Left coord of DIBadMount alert in screen coords}
  425.             kSysAlertTop  = 80; {Top coord of DIBadMount alert in screen coords}
  426.  
  427.         VAR
  428.             cornerPoint: Point; {Top-left corner of DIBadMount alert}
  429.             error:       OSErr;
  430.  
  431.     BEGIN
  432.         IF HiWord (anEvent.message) <> noErr THEN
  433.             BEGIN
  434.                 SetPt ((*<*)cornerPoint, kSysAlertLeft, kSysAlertTop);
  435.                 error := DIBadMount (cornerPoint, anEvent.message)
  436.             END
  437.     END;
  438.  
  439.  
  440. {$S Main}
  441. (*******************************************************************************
  442. * Public: DoOSEvt
  443. *
  444. * When an OS Event is received, it can be a suspend or resume event.
  445. *******************************************************************************)
  446.  
  447.     PROCEDURE DoOSEvt (anEvent: EventRecord);
  448.  
  449.         VAR
  450.             eventWindow: WindowPtr; {Pointer to window being activated/deactivated}
  451.             osEvtKind:   Byte;      {Kind of OSEvt; mouse-moved or suspend/resume}
  452.  
  453.     BEGIN
  454.         (* Only care if anEvent is suspend/resume event *)
  455.         osEvtKind := BAND (BSR (anEvent.message, 24), $00FF);
  456.         IF osEvtKind = suspendResumeMessage THEN
  457.             BEGIN
  458.                 (* It’s a suspend/resume event; suspend or resume? *)
  459.                 eventWindow := FrontWindow;
  460.                 IF BAND (anEvent.message, 1) <> 0 THEN
  461.                     BEGIN
  462.                         (* Resume event; set the cursor and activate front window *)
  463.                         InitCursor;
  464.                         IF eventWindow <> NIL THEN
  465.                             DoActivateEvt (eventWindow, kBecomingActive);
  466.                         gWereInFront := TRUE
  467.                     END
  468.                 ELSE
  469.                     BEGIN
  470.                         (* Suspend event; deactivate the front window *)
  471.                         IF eventWindow <> NIL THEN
  472.                             DoActivateEvt (eventWindow, NOT kBecomingActive);
  473.                         gWereInFront := FALSE
  474.                     END
  475.             END
  476.     END;
  477.  
  478.  
  479. {$S Main}
  480. (*******************************************************************************
  481. * DoHighLevelEvent - Handle a high-level event
  482. *
  483. * This routine handles the high-level event specified by anEvent.  The only
  484. * high-level events that this application handles are AppleEvents, so I just
  485. * pass the high-level event to AEProcessAppleEvent.  AEProcessAppleEvent calls
  486. * the appropriate AppleEvent handler routine to handle that particular kind of
  487. * AppleEvent.
  488. *******************************************************************************)
  489.  
  490.     PROCEDURE DoHighLevelEvent (anEvent: EventRecord);
  491.  
  492.         VAR
  493.             error: OSErr;
  494.  
  495.     BEGIN
  496.         error := AEProcessAppleEvent (anEvent);
  497.     END;
  498.  
  499.  
  500. {$S Main}
  501. (*******************************************************************************
  502. * EventLoop - Main event loop for this application
  503. *
  504. * This is the main event loop of this application.  During every iteration of
  505. * the event loop, the menus are kept up-to-date, and the Process List window and
  506. * all of the open Process Information windows are given time to update
  507. * themselves to current conditions.  Also, NoEmergMem is called to detect
  508. * whether the emergency memory was used.  If it was, then RecoverEmergMem is
  509. * called in an attept to get it back.  If it can’t, then some commands could be
  510. * disabled until the memory can be recovered.
  511. *******************************************************************************)
  512.  
  513.     PROCEDURE EventLoop;
  514.  
  515.         VAR
  516.             anEvent: EventRecord; {An incoming event}
  517.  
  518.     BEGIN
  519.         FixMenus;
  520.         InitCursor;
  521.         gWereInFront := WereInFront;
  522.         gQuitting := FALSE;
  523.  
  524.         (* We loop “forever,” or until the Quit handler calls ExitToShell *)
  525.         WHILE NOT gQuitting DO
  526.             BEGIN
  527.                 (* Give all open windows some time *)
  528.                 IdleAllProcessWindows;
  529.  
  530.                 (* Try to reallocate emergency memory if it’s been used *)
  531.                 IF NoEmergMem THEN
  532.                     RecoverEmergMem;
  533.  
  534.                 (* Fix the menus to reflect current conditions *)
  535.                 FixMenus;
  536.  
  537.                 (* It’s time to get and examine an event *)
  538.                 IF WaitNextEvent (everyEvent, (*<*)anEvent, kMaxSleepTime, NIL) THEN
  539.                     BEGIN
  540.                         CASE anEvent.what OF
  541.                             mouseDown:
  542.                                 DoMouseDown (anEvent);
  543.                             keyDown, autoKey:
  544.                                 DoKeyDown (anEvent);
  545.                             updateEvt:
  546.                                 DoUpdateEvt (anEvent);
  547.                             diskEvt:
  548.                                 DoDiskEvt (anEvent);
  549.                             activateEvt:
  550.                                 DoActivateEvt (WindowPtr(anEvent.message),
  551.                                         BAND (anEvent.modifiers, activeFlag) <> 0);
  552.                             osEvt:
  553.                                 DoOSEvt (anEvent);
  554.                             kHighLevelEvent:
  555.                                 DoHighLevelEvent (anEvent)
  556.                         END
  557.                     END
  558.             END
  559.     END;
  560.  
  561.  
  562. BEGIN
  563.     (* Set up the heap *)
  564.     MaxApplZone;
  565.     MoreMasters;
  566.     MoreMasters;
  567.     MoreMasters;
  568.     MoreMasters;
  569.     MoreMasters;
  570.     MoreMasters;
  571.  
  572.     (* Do anything that must be done at program start-up *)
  573.     StartUp;
  574.     UnloadSeg (@StartUp);
  575.  
  576.     (* Set the default launch mode *)
  577.     SetLaunchMode (kJustLaunch);
  578.  
  579.     (* Open the process list window *)
  580.     gProcessListWind := CreateProcessListWindow;
  581.  
  582.     (* Enter the main event loop *)
  583.     EventLoop
  584. END.
  585.